#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>

#include "My_Button_drv.h"



struct iomux { // 寄存器手册第1543页
    volatile unsigned int unnames[23];
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00; /* offset 0x5c */
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO01;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO02;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO05;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO08;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA;
    volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B;
};


struct imx6ull_gpio { // 寄存器手册第1357页
	volatile unsigned int dr;
	volatile unsigned int gdir;
	volatile unsigned int psr;
	volatile unsigned int icr1;
	volatile unsigned int icr2;
	volatile unsigned int imr;
	volatile unsigned int isr;
	volatile unsigned int edge_sel;
};

/* enable GPIO5 寄存器手册第700页 */
static volatile unsigned int *CCM_CCGR1;

/* enable GPIO4 寄存器手册第703页 */
static volatile unsigned int *CCM_CCGR3; 

/* set GPIO5_IO01 as GPIO 寄存器手册第1500页 */
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1;

/* set GPIO4_IO14 as GPIO 寄存器手册第1653页 */
static volatile unsigned int *IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B;

static struct iomux *iomux;
static struct imx6ull_gpio *gpio4;
static struct imx6ull_gpio *gpio5;


void my_button_init(int which)
{
	if (!CCM_CCGR1) // 判断如果CCM_CCGR1寄存器没有被重映射过
	{
		CCM_CCGR1 = ioremap(0x20C406C, 4);
		CCM_CCGR3 = ioremap(0x20C4074, 4);
		IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = ioremap(0x229000C, 4);
		IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B = ioremap(0x20E01B0, 4);

		iomux = ioremap(0x20E0000, sizeof(struct iomux));
		gpio4 = ioremap(0x20A8000, sizeof(struct imx6ull_gpio));
		gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));
	}

	if (which == 0) // Key1, GPIO5_1
	{
		*CCM_CCGR1 |= (3<<30);
		*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = 5; // 0b0101
		gpio5->	gdir &= ~(1<<1); // 寄存器手册第1359页
	}
	else if (which == 1) // Key2, GPIO4_14
	{
		*CCM_CCGR3 |= (3<<11);
		*IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B = 5; // 0b0101
		gpio4->gdir &= ~(1<<14); // 寄存器手册第1359页
	}
	//else
	//{
	//	printk("Unknown assignment %d!\n", which);
	//}
	
	// printk("%s %s %d, init gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);
}

int my_button_read(int which) // 返回1表示按下，0表示没按下
{
	if (which == 0) // Key1, GPIO5_1
		return (gpio5->psr & (1<<1)) ? 0 : 1; // 寄存器手册第1359页

	else if (which == 1) // Key2, GPIO4_14
		return (gpio4->psr & (1<<14)) ? 0 : 1; // 寄存器手册第1359页

	else
		return -1;

	// printk("%s %s %d, read gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);
}

// 只是实现伪按键检测
static struct button_operations my_button_opts = {
	.count  = 2,
	.init = my_button_init,
	.read = my_button_read,
};



static int __init board_init(void)
{
	button_create(&my_button_opts);
	return 0;
}

static void  __exit board_exit(void)
{
	button_destroy();
}

module_init(board_init);
module_exit(board_exit);
MODULE_LICENSE("GPL");




